package com.demo.seckill.web;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.demo.seckill.entity.SuccessKilled;
import com.demo.seckill.enums.SeckillStatEnum;
import com.demo.seckill.service.ISeckillService;
import com.demo.seckill.service.ISuccessKilledService;
import com.demo.utils.RedisUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

import java.util.concurrent.*;

/**
 * @author : YU.TAN
 * @date : 2021/10/26 14:55
 */
@Api(tags = "分布式秒杀")
@RestController
@RequestMapping("/seckillDistributed")
@Slf4j
public class SeckillDistributedController {

    private static int corePoolSize = Runtime.getRuntime().availableProcessors();
    /**
     * 空闲线程存活时间
     */
    private static long keepAliveTime = 10L;

    /**
     * 创建线程池  调整队列数 拒绝服务
     */
    private static ThreadPoolExecutor poolExecutor = new ThreadPoolExecutor(corePoolSize, corePoolSize + 1, keepAliveTime, TimeUnit.SECONDS
            //线程等待队列
            , new LinkedBlockingQueue<>(10000)
            //默认线程工厂
            , Executors.defaultThreadFactory()
            //线程池拒绝策略
            , new ThreadPoolExecutor.AbortPolicy());


    @Autowired
    private ISeckillService seckillService;
    @Autowired
    private ISuccessKilledService successKilledService;
    @Autowired
    private RedisUtil redisUtil;


    @ApiOperation(value = "秒杀一(Rediss分布式锁)")
    @RequestMapping(value = "/start/one", method = RequestMethod.GET)
    public void startOne(long seckillId) {
        CountDownLatch latch = new CountDownLatch(100);
        log.info("秒杀开始：Id={}", seckillId);
        for (int i = 1; i <= 2000; i++) {
            long userId = i;
            Runnable task = () -> {
                try {
                    SeckillStatEnum statEnum = seckillService.startDistributedOneSeckill(seckillId, userId);
                    if (statEnum != null) {
                        log.info("用户userId={},秒杀结果={}", userId, statEnum.getInfo());
                    } else {
                        log.info("用户:{}{}", userId, "哎呦喂，人也太多了，请稍后！");
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                    log.info("服务器错误！");
                }
                latch.countDown();
            };
            poolExecutor.execute(task);
        }
        try {
            latch.await();
            int count = successKilledService.count(new LambdaQueryWrapper<SuccessKilled>()
                    .eq(SuccessKilled::getSeckillId, seckillId));
            log.info("活动{}一共秒杀商品{}件", seckillId, count);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 现将商品数量缓存进redis
     * redis判断库存-》加锁-》执行业务-》释放锁
     *
     * @param seckillId
     */
    @ApiOperation(value = "秒杀一(Rediss分布式锁+原子递减)")
    @RequestMapping(value = "/start/two", method = RequestMethod.GET)
    public void startTwo(long seckillId) {
        log.info("秒杀开始：Id={}", seckillId);
        for (int i = 0; i < 2000; i++) {
            long userId = i;
            //判断库存
            Integer restNumberA = Integer.parseInt((String)redisUtil.get(seckillId + "_num")) ;
            if(restNumberA<=0){
                continue;
            }
            Long restNumber = redisUtil.decr(seckillId + "_num", 1);
            if (restNumber >= 0) {
                Runnable task = () -> {
                    try {
                        SeckillStatEnum statEnum = seckillService.startDistributedTwoSeckill(seckillId, userId);
                        if (statEnum != null) {
                            log.info("用户userId={},秒杀结果={}", userId, statEnum.getInfo());
                        } else {
                            log.info("用户:{}{}", userId, "哎呦喂，人也太多了，请稍后！");
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                };
                poolExecutor.execute(task);
            } else {
                log.info("用户:{}{}", userId, "秒杀结束！");
            }
        }


    }

}
